#include "stdafx.h"
#include "MessageFactory.h"
#include "GalconTypes.h"
#include <boost/algorithm/string.hpp>
#include "InitialGameStateMessage.h"
#include "PlanetInternalImpl.h"
#include "PlayerInternalImpl.h"
#include "Game.h"
#include "GameStateMessage.h"
#include "GameState.h"
#include "FlightInfoFwd.h"
#include "FlightInfo.h"
#include "ShipsLaunchedMessage.h"
#include "ErrorDescriptionMessage.h"
#include "RejectionMessage.h"

template<typename Iter>
GameInitInfoPtr ParseGameInitInfo(Iter begin, Iter end)
{
   if (*begin != "Player")
      throw std::exception("MessageFactory: wrong message in buildInitialGameStateMessage");
   //Player id col Planets id coordX coordY player_id count_of_ships id coordX coordY player_id count_of_ships ... Players id col ...
   ++begin;
   PlayerID currentPlayerID = PlayerID(atoi(begin->c_str()));
   ++begin;
   GameColors playerColor = GameColors(atoi(begin->c_str()));
   ++begin;
   if (*begin++ != "Planets")
      throw std::exception("MessageFactory: wrong message in buildInitialGameStateMessage");
   double xCoord;
   double yCoord;
   PlayerID playerID;
   PlanetID planetID;
   unsigned int countOfShips;
   PlanetSize planetSize;
   GamePlanets textureId;
   PlanetInternalImplPtr currentPlanet;

   PlanetsInitInfoVector planets;
   //"3 0 Player 0 0 Planets 0 0.1 0.1 0 40 1 7 1 0.3 0.12 1 40 2 7 2 0.6 0.15 -1 40 4 7 3 0.9 0.25 -1 40 3 7 4 0.2 0.3 -1 40 2 7 5 0.45 0.5 -1 40 0 7 6 0.8 0.4 -1 40 4 7 7 0.15 0.9 -1 40 3 7 8 0.55 0.6 -1 40 2 7 9 0.85 0.65 -1 40 2 7 Players 0 0 1 1"
   do
   {
      planetID = PlanetID(atoi((begin++)->c_str()));
      xCoord = atof((begin++)->c_str());
      yCoord = atof((begin++)->c_str());
      playerID = PlayerID(atoi((begin++)->c_str()));
      countOfShips = unsigned(atoi((begin++)->c_str()));
      planetSize = PlanetSize(atoi((begin++)->c_str()));
      textureId = GamePlanets(atoi((begin++)->c_str()));
      currentPlanet = boost::make_shared<PlanetInternalImpl>(planetID, countOfShips, playerID, 
                                                             xCoord, yCoord, planetSize, textureId);
      planets.push_back(currentPlanet);

   } while (*begin != "Players");
   
   ++begin;
   PlayerInternalImplPtr player;
   PlayersInitInfoVector players;

   while (begin != end)
   {
      playerID = PlayerID(atoi((begin++)->c_str()));
      playerColor = GameColors(atoi((begin++)->c_str()));
      player = boost::make_shared<PlayerInternalImpl>(playerID, playerColor);
      players.push_back(player);
   }

   GameInitInfoPtr gameInfo = boost::make_shared<GameInitInfo>(currentPlayerID, planets, players);
   return gameInfo;
}

template<typename Iter>
GameStatePtr ParseGameState(Iter begin, Iter end)
{
   if (*begin++ != "Planets")
      throw std::exception("MessageFactory: ParseGameState wrong message format.");

   GameStatePtr gameStatePtr = boost::make_shared<GameState>();
   PlanetInternalImplPtr currentPlanet;
   PlanetID planetID;
   unsigned int countOfShips;
   PlayerID playerID;

   do
   {
      planetID = PlanetID(atoi((begin++)->c_str()));
      playerID = PlayerID(atoi((begin++)->c_str()));
      countOfShips = unsigned(atoi((begin++)->c_str()));
      currentPlanet = boost::make_shared<PlanetInternalImpl>(planetID, countOfShips, playerID);
      gameStatePtr->AddPlanet(planetID, currentPlanet);
   } while(*begin != "Players");

   ++begin;
   GameColors playerColor;
   PlayerInternalImplPtr currentPlayer;

   while (begin != end)
   {
      playerID = PlayerID(atoi((begin++)->c_str()));
      playerColor = GameColors(atoi((begin++)->c_str()));
      currentPlayer = boost::make_shared<PlayerInternalImpl>(playerID, playerColor);
      gameStatePtr->AddPlayer(playerID, currentPlayer);
   }

   return gameStatePtr;
}

template<typename Iter>
std::string ParseErrorDescription(Iter begin, Iter end)
{
   std::string message;
   while (begin != end)
   {
      message += *begin++ + " ";
   }
   return message;
}

template<typename Iter>
std::string ParseRejectionDescription(Iter begin, Iter end)
{
   std::string message;
   while (begin != end)
   {
      message += *begin++ + " ";
   }
   return message;
}
MessageFactory::MessageFactory(GalconClientPtr galconClient, GamePtr gamePtr, boost::shared_ptr<QGraphicsView> graphicsView)
   : m_galconPtr(galconClient)
   , m_gamePtr(gamePtr)
   , m_graphicsView(graphicsView)
{
}


MessageFactory::~MessageFactory()
{
}


template<typename Iter>
MessageBasePtr MessageFactory::buildInitialGameStateMessage( Iter begin, Iter end )
{
   GameInitInfoPtr gameInitInfoPtr = ParseGameInitInfo(begin, end);
   InitialGameStateMessagePtr message = boost::make_shared<InitialGameStateMessage>(m_gamePtr, gameInitInfoPtr);
   return message;
}

template<typename Iter>
MessageBasePtr MessageFactory::builGameStateMessage( Iter begin, Iter end )
{
   GameStatePtr gameStatePtr = ParseGameState(begin, end);
   MessageBasePtr message = boost::make_shared<GameStateMessage>(m_gamePtr, gameStatePtr);
   return message;
}

template<typename Iter>
MessageBasePtr MessageFactory::buildShipsLaunchedMessage( Iter begin, Iter end )
{
   FlightInfoPtr flightInfoPtr = ParseShipsLaunched(begin, end);
   MessageBasePtr message = boost::make_shared<ShipsLaunchedMessage>(m_gamePtr, flightInfoPtr);
   return message;
}

template<typename Iter>
MessageBasePtr MessageFactory::buildErrorDescriptionMessage( Iter begin, Iter end )
{
   std::string errorDescription = ParseErrorDescription(begin, end);
   MessageBasePtr messagePtr = boost::make_shared<ErrorDescriptionMessage>(errorDescription);
   return messagePtr;
}

template<typename Iter>
MessageBasePtr MessageFactory::buildRejectionMessage( Iter begin, Iter end )
{
   std::string rejectionMessage = ParseRejectionDescription(begin, end);
   MessageBasePtr messagePtr = boost::make_shared<RejectionMessage>(m_galconPtr, rejectionMessage);
   return messagePtr;
}

MessageBasePtr MessageFactory::do_parseMessage( MessagesEnum messageType, split_vector_type_iter begin, split_vector_type_iter end)
{
   switch (messageType)
   {
   case ShipsLaunched:
      {
         return buildShipsLaunchedMessage(begin, end);
      }
      break;
   case InitialMessage:
      {
         return buildInitialGameStateMessage(begin, end);
      }
      break;
   case PingMessage:
      {
         return builGameStateMessage(begin, end);
      }
      break;
   case TooManyPlayers:
      {
         return buildRejectionMessage(begin,end);
      }
      break;
   case ErrorMessage:
      {
         return buildErrorDescriptionMessage(begin, end);
      }
      break;
   default:
      {
         throw std::exception("MessageFactory: wrong message type in ParseMessage");
      }
      break;
   }
}